/*
 * 文件名：WeXinUtil.java
 * 版权：© Copyright 2012-2018 广州宝锶信息技术有限公司
 * 创建人：曾毅
 * 创建时间：2017年4月29日 上午12:24:43
 * 修改人：
 * 修改时间：
 * 需改内容：
 * 
 */
package com.baothink.weichat.utils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.baothink.weichat.dto.base.AWeichatMsgTypeContent;
import com.baothink.weichat.dto.base.WeichatMsgBaseDto;
import com.baothink.weichat.dto.base.WeichatMsgBaseDto.WeXinMsgResponseDto;
import com.baothink.weichat.dto.common.AccessToken;
import com.baothink.weichat.dto.common.WeiChatLoginUser;
import com.baothink.weichat.dto.common.WeichatAgentInfo;
import com.baothink.weichat.dto.common.WeichatAgentInfo.AllowPartys;
import com.baothink.weichat.dto.common.WeichatAgentInfo.AllowTags;
import com.baothink.weichat.dto.common.WeichatAgentInfo.AllowUserinfos;
import com.baothink.weichat.dto.common.WeichatAgentInfo.User;
import com.baothink.weichat.dto.msg.WeichatTextMsgDto;
import com.baothink.weichat.dto.msgtype.TextMsg;
import com.baothink.weichat.enumer.WeXinConfig;
import com.baothink.weichat.exception.WechatException;


/**
 * 微信工具类
 * 
 * @author  曾毅
 * @version 1.0，2017年4月29日 上午12:24:43
 * @param <B>
 * @since   ASSCWeb1.0
 */
@SuppressWarnings("resource")
public class WechatUtil_bak {
    
    public static Logger log = LoggerFactory.getLogger(WechatUtil_bak.class);
    
    public static Properties properties;
    
    private static WeichatAgentInfo weiXinAgentInfo;
    
    private static final Long AGENT_INFO_RE_GET_TIME=1000*60*5L;
    
    public static final String PROPERTIES_NAME = "WeXinConfig";
    
    public static final String KEY_ACCESS_TOKEN = "access_token";
    
    public static final String KEY_USER_ID = "UserId";
    
    private static final String TOKEN_KEY_DELIMITER = "@";
    
    /** 
     * 每个权限管理组对应一个accessToken  key:权限管理组secret
     */
    private static final Map<String, AccessToken> tokenMap = new ConcurrentHashMap<>(); 
    
    static{
        properties = new Properties();
        Properties loadProperties = new Properties();
        InputStream is = null;
        try {
            String propertiesPath = null;
            try{
                is = WechatUtil_bak.class.getClassLoader().getResourceAsStream(PROPERTIES_NAME+"Default.properties");
                loadProperties.load(is);
                properties.putAll(loadProperties);
                if(log.isDebugEnabled()){
                    log.debug("the weixin config properties is loaded from default path,properties:"+properties);
                }
            } catch (Exception e2) {
                e2.printStackTrace();
                throw new Exception("load weixin default config properties failed ");
            }
            
            try {
                propertiesPath = PathUtil.getClassResources()+PROPERTIES_NAME+".properties";
                is = new FileInputStream(propertiesPath);
                loadProperties.load(is);
                properties.putAll(loadProperties);
                if(log.isDebugEnabled()){
                    log.debug("the weixin config properties is loaded from path："+propertiesPath+",properties:"+properties);
                }
            } catch (Exception e) {
                if(log.isWarnEnabled()){
                    log.warn("the weixin config properties load failed from path："+propertiesPath);
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }finally{
            if(null!=is){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    
    
    /**  
     * 获取内置token
     * 
     * @return
     * @since ASSCWeb1.0
     */
    public static String getPrivateAccessToken(){
        return getAccessToken(getWeXinConfig(WeXinConfig.CORPID), getWeXinConfig(WeXinConfig.CORPSECRET));
    }
    
    /**  
     * 获取token
     * 
     * @param corpId
     * @param corpsecret
     * @return
     * @since ASSCWeb1.0
     */
    public static String getAccessToken(String corpId,String corpsecret){
        if(tokenMap.containsKey(corpsecret)&&tokenMap.get(corpsecret).isAvailable()){
        	log.debug(String.format("token surplus valid time --> %d", tokenMap.get(corpsecret).getSurplusValidTime()));
            return tokenMap.get(corpsecret).getAccess_token();
        }else{
            Map<String, String> paramMap = new HashMap<String, String>();
            paramMap.put("corpId", corpId);
            paramMap.put("corpsecret", corpsecret);
            String response = doGet(getWeXinConfig(WeXinConfig.URL_TOKEN), paramMap);
            if(!StringUtil.isEmptyOrNull(response)){
               AccessToken accessToken = JSONUtil.toBean(response, AccessToken.class);
               accessToken.setGetTime(System.currentTimeMillis());
               tokenMap.put(corpsecret, accessToken);
               return accessToken.getAccess_token();
            }
        }
        return null;
    }
    
    /**  
     * 获取用户信息
     * 
     * @param code
     * @return
     * @since ASSCWeb1.0
     */
    public static WeiChatLoginUser getPrivateUserInfo(String code){
        String privateAccessToken = getPrivateAccessToken();
        return getUserInfo(privateAccessToken, code);
    }
    
    /**  
     * 通过USERCODE获取用户信息
     * 
     * @param accessToken
     * @param code   用户代码
     * @return
     * @since ASSCWeb1.0
     */
    public static WeiChatLoginUser getUserInfo(String accessToken,String code){
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put(KEY_ACCESS_TOKEN, accessToken);
        paramMap.put("code",  code);
        
        String response = doGet(getWeXinConfig(WeXinConfig.URL_GETUSERINFO), paramMap);
        
        WeiChatLoginUser user = JSONUtil.toBean(response, WeiChatLoginUser.class);
        user.setGetTime(System.currentTimeMillis());
        return user;
    }
    
    public static void reLoginUser(WeiChatLoginUser user) throws WechatException{
    	if(StringUtil.isEmptyOrNull(user.getUserId())){
    		throw new WechatException("用户代码为空，无法重新登录");
    	}
    }
    
    /**  
     * 获取消息中心应用信息 
     * 
     * @return
     * @since ASSCWeb1.0
     */
    public static WeichatAgentInfo getMessageAgentInfo(){
        if(weiXinAgentInfo!=null){
            long getInfoTime = weiXinAgentInfo.getGetInfoTime();
            if(System.currentTimeMillis()-getInfoTime<AGENT_INFO_RE_GET_TIME){
                return weiXinAgentInfo;
            }
        }
        String agentId = getWeXinConfig(WeXinConfig.AGENT_TEXT_ID);
        weiXinAgentInfo = getAgentInfo(agentId);
        weiXinAgentInfo.setGetInfoTime(System.currentTimeMillis());
        return weiXinAgentInfo;
    }
    
    /**  
     * 获取应用信息
     * 
     * @since ASSCWeb1.0
     */
    public static WeichatAgentInfo getAgentInfo(String agentId){
        Map<String,String> paramMap = getAccessTokenMap();
        paramMap.put("agentid", agentId);
        String url = getWeXinConfig(WeXinConfig.URL_AGENT_INFO);
        String response = doGet(url, paramMap);
        System.out.println(response);
        Map<String,Class<?>> clzMap = new HashMap<>();
        clzMap.put("allow_userinfos", AllowUserinfos.class);
        clzMap.put("allow_partys",AllowPartys.class);
        clzMap.put("allow_tags",AllowTags.class);
        clzMap.put("user", User.class);
        return JSONUtil.toBean(response, WeichatAgentInfo.class);
    }
    
    /**  
     * 发送文本消息
     * 
     * @param touser
     * @param toparty
     * @param totag
     * @param msg
     * @return
     * @throws WechatException 
     * @since WeiXinUtil1.0
     */
    public static WeXinMsgResponseDto sendTextMessage(String touser,String toparty,String totag,String msg){
//        WeiXinAgentInfo agentInfo = getMessageAgentInfo();
//        if(agentInfo.hasPrivileges(touser)){
            WeichatTextMsgDto dto = new WeichatTextMsgDto();
            dto.setAgentid(getWeXinConfig(WeXinConfig.AGENT_TEXT_ID));
            dto.setTouser(touser);
            dto.setToparty(toparty);
            dto.setTotag(totag);
            TextMsg textMsg = new TextMsg();
            textMsg.setContent(msg);
            return sendMessage(dto, textMsg);
//        }else{
//            throw new WechatException(String.format("there is someone don't access the message application ,applicationId【%s】--userlist【%s】--acessUserlist【%s】", getWeXinConfig(WeXinConfig.AGENT_TEXT_ID),touser,agentInfo.getAllowUsers()));
//        }
    }
    
    /**  
     * 获取部门列表信息
     * 
     * @param deptId
     * @return
     * @since WeiXinUtil1.0
     */
    public static String getDeptList(String deptId){
        String url = getWeXinConfig(WeXinConfig.URL_DEPT_LIST);
        Map<String, String> paramMap = getAccessTokenMap();
        paramMap.put("id", deptId);
        String response = doGet(url, paramMap);
        return response;
    }
    
    /**  
     * 获取成员信息
     * 
     * @param userid
     * @return
     * @since WeiXinUtil1.0
     */
    public static String getUserInfo(String userid){
        String url = getWeXinConfig(WeXinConfig.URL_USER_INFO);
        Map<String, String> paramMap = getAccessTokenMap();
        paramMap.put("userid", userid);
        String response = doGet(url, paramMap);
        return response;
    }
    
    /**  
     * 发送消息
     * 
     * @param touser
     * @param toparty
     * @param totag
     * @param b
     * @param t
     * @return
     * @since ASSCWeb1.0
     */
    public static <B extends WeichatMsgBaseDto<T>,T extends AWeichatMsgTypeContent> WeXinMsgResponseDto sendMessage(String touser,String toparty,String totag,Class<B> b,T t){
        try {
            B instance = b.newInstance();
            instance.setTouser(touser);
            instance.setToparty(toparty);
            instance.setTotag(totag);
            return sendMessage(instance, t);
        } catch (Exception e) {
            e.printStackTrace();
        }   
        return null;
     }
    
    /**  
     * 发送消息
     * 
     * @param b
     * @param t
     * @return
     * @since ASSCWeb1.0
     */
    public static <B extends WeichatMsgBaseDto<T>,T extends AWeichatMsgTypeContent> WeXinMsgResponseDto sendMessage(B b,T t){
       try {
           b.confirmMsgType(t);
           return sendMessage(b);
       } catch (Exception e) {
           e.printStackTrace();
       }   
       return null;
    }
    
    /**  
     * 发送消息
     * 
     * @param message
     * @return
     * @since ASSCWeb1.0
     */
    public static <T extends WeichatMsgBaseDto<? extends AWeichatMsgTypeContent>> WeXinMsgResponseDto sendMessage(T t){
        String url = getWeXinConfig(WeXinConfig.URL_SENDMESSAGE);
        Map<String,String> placeMap = getAccessTokenMap();
        url = fillParamToUrl(url, placeMap);
        try {
            String response = doPost(url, JSONUtil.toJsonString(t));
            return JSONUtil.toBean(response, WeXinMsgResponseDto.class);
        } catch (WechatException e) {
            e.printStackTrace();
        }
        return null;
    }
    
    /**  
     * GET请求
     * 
     * @param url
     * @param paMap
     * @return
     * @since ASSCWeb1.0
     */
    private static String doGet(String url,Map<String,String> paMap){
        CloseableHttpClient client = HttpClients.createDefault(); 
        String response="";
        if(StringUtil.isEmptyOrNull(url)){
            return response;
        }
        StringBuilder sb =new StringBuilder();
        try {
            if(null!=paMap&&paMap.size()>0){
                sb.append("?");
                Iterator<Entry<String, String>> it = paMap.entrySet().iterator();
                while(it.hasNext()){
                    Entry<String, String> next = it.next();
                    String paramName=next.getKey();
                    String paramValue=next.getValue();
                    if(!StringUtil.isEmptyOrNull(paramValue)){
                        paramValue=URLEncoder.encode(paramValue);
                    }
                    sb.append("&").append(paramName).append("=").append(paramValue);
                }
                sb.replace(1, 2, "");
            }
            String paramPrefix=sb.toString();
            if(!StringUtil.isEmptyOrNull(paramPrefix)){
                url+=paramPrefix;
            }
            log.debug("请求地址："+url);
            HttpGet httpGet=new HttpGet(url);
            
            HttpResponse res = client.execute(httpGet);
            if(res.getStatusLine().getStatusCode()==HttpStatus.SC_OK){
                response = EntityUtils.toString(res.getEntity(), Charset.forName("UTF-8").toString());
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.debug("请求返回参数"+response);
        return response;
    } 
    
    /**  
     * POST请求
     * 
     * @param url
     * @param json
     * @return
     * @throws WechatException
     * @since ASSCWeb1.0
     */
    private static String doPost(String url,String json) throws WechatException {
        CloseableHttpClient client = HttpClients.createDefault(); 
        HttpPost post = new HttpPost(url);
        String response = null;
        log.debug("请求地址："+url);
        try {
            StringEntity entity = new StringEntity(json,"utf8");
            entity.setContentEncoding("UTF-8");
            entity.setContentType("text/json; charset=UTF-8");// 发送json数据需要设置contentType
            post.setEntity(entity);
            HttpResponse res = client.execute(post);
            if (res.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                response = EntityUtils.toString(res.getEntity(), Charset
                        .forName("UTF-8").toString());// 返回json格式：
            } else {
                throw new WechatException("请求失败"+EntityUtils.toString(res.getEntity(), Charset.forName("UTF-8").toString()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        log.debug("请求返回参数"+response);
        return response;
    }
   
    /**  
     * 获取认证地址
     * 
     * @param redirectUrl
     * @return
     * @since ASSCWeb1.0
     */
    public static String getAuthorizeUrl(String redirectUrl){
        String paramStr = "?appid={corpId}&redirect_uri={redirectUrl}&response_type=code&scope=snsapi_base&agentid={agentid}&state=1231#wechat_redirect";
        String url = getWeXinConfig(WeXinConfig.URL_AUTHORIZE)+paramStr;
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("corpId", getWeXinConfig(WeXinConfig.CORPID));
        paramMap.put("redirectUrl", redirectUrl);
        paramMap.put("agentid", getWeXinConfig(WeXinConfig.AGENT_EMAIL_ID));
        return PlaceholderUtils.resolvePlaceholders(url, paramMap);
    }
    
    /**  
     * 获取微信配置参数
     * 
     * @param config
     * @return
     * @since ASSCWeb1.0
     */
    public static String getWeXinConfig(WeXinConfig config){
        return properties.getProperty(config.name());
    }
    
    /**  
     * 返回存放token的map
     * 
     * @return
     * @since ASSCWeb1.0
     */
    private static Map<String,String> getAccessTokenMap(){
        Map<String,String> reMap = new HashMap<>();
        reMap.put("access_token", getPrivateAccessToken());
        return reMap;
    }
    
    /**  
     * 拼接URL
     * 
     * @param url
     * @param placeMap
     * @return
     * @since ASSCWeb1.0
     */
    private static String fillParamToUrl(String url,Map<String,String> paramMap){
        if(null==paramMap){
            return url;
        }
        StringBuffer sb = new StringBuffer(url);
        sb.append("?");
        for(Map.Entry<String, String> entry:paramMap.entrySet()){
            String key = entry.getKey();
            String value = entry.getValue();
            sb.append(key).append("=").append(value).append("&");
        }
        sb.delete(sb.length()-1, sb.length());
        return sb.toString();
    }
    
    public static void main(String[] args) {
        try {
//            String str="hello";
//            WeiXinAgentInfo agentInfo = getMessageAgentInfo();
//            String allowUsers = agentInfo.getAllowUsers();
//            System.out.println(agentInfo.hasPrivileges("00010"));
//            TextMsg textMsg = new TextMsg();
//            textMsg.setContent("邮件提醒");
//            WeXinMsgResponseDto sendTextMessage = sendTextMessage("zengy", "", "", "邮件提醒");
//            System.out.println(sendTextMessage);
//            System.out.println(getMessageAgentInfo());
//            System.out.println(getDeptList("1"));
//            System.out.println(getUserInfo("784633"));
        	String uri = "http://17t018u429.iask.in:22665/spring-mvc/weichat/toVisual";
        	System.out.println(URLEncoder.encode(uri,Charset.forName("utf-8").name()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        
    }
}
